#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include<unistd.h>
#include<pwd.h>
#include<sys/stat.h>
#include<shadow.h>
#include<termios.h>
int main(int argc,char *argv[])
{
	//su    root
	//su username      username
	//Password:      (not show)
	char *user="root";
	
	if(argv[1]!=NULL)
	{
		
	
		user=argv[1];
		struct passwd *p=NULL;
		p=getpwnam(user);
		if(p==NULL)
		{
		printf("not find username!\n");
		return;
		}
	
	}
	struct passwd *pw=getpwuid(getuid());
	
	
	//input password
	//
	//
	if(strcmp(pw->pw_name,"root")!=0)
	{
	char passwd[128]={0};
	printf("Passwd:");
	struct termios old,new;
	tcgetattr(0,&old);
	new=old;
	new.c_lflag &= ~ECHO;   //huixian
	new.c_lflag &= ~ICANON; //feibiaozhun
	tcsetattr(0,TCSANOW,&new);
	//fgets(passwd,128,stdin);//linux chengxusheji 5.4
    char c=0;
	int num=0;
	while((c=getchar())!='\n')
	{
		if(c==127)
		{
		    if(num>0)
			{
			passwd[--num]=0;	
		    printf("\033[1D");
			printf("\033[K");
			}
			continue;
		}
	printf("*");
	fflush(stdout);
	passwd[num++]=c;
	}
	tcsetattr(0,TCSANOW,&old);

	//passwd[strlen(passwd)-1]=0;
    printf("\n");
	struct spwd *sp=getspnam(user);
	assert(sp!=NULL);
  //	printf("%s\n",sp->sp_pwdp);

    char salt[128]={0};
	int i=0;
	int count =0;
	for(;sp->sp_pwdp[i]!=0;i++)
	{
	  salt[i]=sp->sp_pwdp[i];
	  if(salt[i]=='$')
	  {
	     count++;
	   if(count==3)
		   break;
	  }
	}
  //gcc -o su su.c  -lcrypt
	char* p=crypt(passwd,salt);
	assert(p!=NULL);
   

	
	if(strcmp(p,sp->sp_pwdp)!=0)
	{
	 printf("passwd error\n");
	 exit(0);
	
	}
    }
	////////////////////
	
	pid_t pid=fork();
	assert(pid!=-1);
	
	if(pid==0)
	{
		struct passwd *pw=getpwnam(user);
		assert(pw!=NULL);
        setuid(pw->pw_uid);
		setenv("HOME",pw->pw_dir,1);
		execl(pw->pw_shell,pw->pw_shell,(char *)0);
	    printf("error\n");
		exit(0);
	
	}

	else
		wait(NULL);

	return 0;
}
